package com.yikome.shop.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.yikome.common.CommonService;
import com.yikome.constant.StatusConstant;
import com.yikome.product.dto.ProductDTO;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.yikome.shop.dto.CollectionCoverDTO;
import com.yikome.shop.dto.CollectionDTO;
import com.yikome.shop.dto.CollectionEditDTO;
import com.yikome.shop.entity.Collection;
import com.yikome.shop.entity.CollectionProduct;
import com.yikome.shop.repository.CollectionProductRepository;
import com.yikome.shop.repository.CollectionRepository;
import com.yikome.shop.request.CollectionRequest;
import com.yikome.utils.BeanUtils;
import com.yikome.utils.JSONUtils;
import com.yikome.utils.NamedParameterJdbcUtils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class CollectionService extends CommonService<Collection, Long>{

	@Autowired
	private CollectionRepository collectionRepository ;
	
	@Autowired
	private CollectionProductRepository collectionProductRepository;
	
	@Autowired
	private NamedParameterJdbcTemplate jdbcTemplate ; 

	@Autowired
	public void setResourceDao(CollectionRepository repository) {
		super.setCommonDao(repository);
	}
	
	public CollectionEditDTO findCollection(Long collectionId) {
		
		Collection collection = collectionRepository.findById(collectionId).orElseGet(null);
		
		if(collection != null) {
			CollectionEditDTO collectionEditDTO = new CollectionEditDTO();
			collectionEditDTO.setName(collection.getName());
			collectionEditDTO.setComments(collection.getComments());
			collectionEditDTO.setCollectionId(collection.getId());
			collectionEditDTO.setBanners(collection.getBanners());
			collectionEditDTO.setPresentId(collection.getPresentId());
			
			List<ProductDTO> productDTOs = findColletionProducts(collectionId);
			for (ProductDTO productDTO : productDTOs) {
				productDTO.setStatusName(StatusConstant.statusName(productDTO.getStatus()));
			}
			collectionEditDTO.setProductDTOs(productDTOs);
			return collectionEditDTO ;
		}
		
		return null;
	}
	
	public List<ProductDTO> findColletionProducts(Long collectionId) {
		String contentSQL = "SELECT \n" + 
							"	p_product.id, p_product.title, p_product.image, p_product.description, p_product.tags, p_product.`status`, p_product.price, \n" + 
							"	p_product_ext.source_type, s_supplier.shop_name supplier_name, p_product_ext.comments \n" + 
							"FROM s_collection_product  \n" + 
							"	LEFT JOIN p_product ON (s_collection_product.product_id = p_product.id) \n" + 
							"	LEFT JOIN p_product_ext ON (p_product.id = p_product_ext.product_id) \n" + 
							"	LEFT JOIN s_supplier ON (p_product_ext.supplier_id = s_supplier.id) \n" + 
							"WHERE 1 = 1 \n" + 
							"AND s_collection_product.collection_id = :collectionId \n" + 
							"AND p_product.yn = 1 \n" + 
							"ORDER BY s_collection_product.priority ASC, p_product.price ASC \n" ; 
		return jdbcTemplate.query(contentSQL, ImmutableMap.of("collectionId", collectionId), new BeanPropertyRowMapper<>(ProductDTO.class));
	}

	public Page<CollectionDTO> findCollection(CollectionRequest collectionRequest , Pageable pageable) {
		
		String contentSQL = "SELECT \n" + 
							"	s_collection.id collectionId, s_collection.`name`, s_collection.comments, s_collection.banners, s_collection.cover_img, \n" + 
							"	(SELECT thumb FROM s_present WHERE s_present.id = s_collection.present_id) thumb, \n" + 
							"   (SELECT COUNT(1) FROM s_collection_product WHERE s_collection_product.collection_id = s_collection.id) productCount \n" + 
							"FROM s_collection \n" ; 
		
		StringBuilder paramsSQL = new StringBuilder("WHERE s_collection.yn = 1 \n");
		Map<String , Object> paramsMap = new HashMap<>();
		
		if(collectionRequest.getCollectionId() != null) {
			paramsSQL.append("AND s_collection.id = :collectionId \n");
			paramsMap.put("collectionId", collectionRequest.getCollectionId());
		}
		if(StrUtil.isNotBlank(collectionRequest.getName())) {
			paramsSQL.append("AND s_collection.`name` like :collectionName \n");
			paramsMap.put("collectionName", StrUtil.wrap(collectionRequest.getName(), "%"));
		}
		if(StrUtil.isNotBlank(collectionRequest.getComments())) {
			paramsSQL.append("AND s_collection.comments like :comments \n");
			paramsMap.put("comments", StrUtil.wrap(collectionRequest.getComments(), "%"));
		}
		
		String orderSQL = NamedParameterJdbcUtils.findOrderSQL(pageable);
    	String pageSQL = NamedParameterJdbcUtils.findPageSQL(pageable);
    	
    	List<CollectionDTO> collectionDTOs = jdbcTemplate.query(contentSQL + paramsSQL + orderSQL + pageSQL , paramsMap, new BeanPropertyRowMapper<CollectionDTO>(CollectionDTO.class));
		
    	Long total = jdbcTemplate.queryForObject("SELECT COUNT(1) FROM (" + contentSQL + paramsSQL + ") T", paramsMap, Long.class);

        return new PageImpl<>(collectionDTOs, pageable, total);
	}

	@Transactional
	public Boolean deleteCollections(List<Long> collectionIds) {
		
		for (Long collectionId : collectionIds) {
			collectionRepository.deleteById(collectionId);
			collectionProductRepository.deleteByCollectionId(collectionId);
		}
		return Boolean.TRUE;
	}
	
	@Transactional
	public Boolean deleteCollection(Long collectionId) {
		
		collectionRepository.deleteById(collectionId);
		collectionProductRepository.deleteByCollectionId(collectionId);
		
		return Boolean.TRUE;
	}

	@Transactional
	public Boolean bindCollectionProducts(Long collectionId, List<Long> products) {
		
		List<CollectionProduct> collectionProducts = new ArrayList<>();
		for (int index = 0 ; index < products.size() ; index++) {
			collectionProducts.add(new CollectionProduct(collectionId, products.get(index), index));
		}
		collectionProductRepository.saveAll(collectionProducts);
		
		return Boolean.TRUE;
	}

	@Transactional
	public Boolean deleteCollectionProducts(List<Long> collectionProductIds) {
		
		String contentSQL = "DELETE FROM s_collection_product WHERE s_collection_product.id IN (:collectionProductIds)";
		
		jdbcTemplate.update(contentSQL, ImmutableMap.of("collectionProductIds", collectionProductIds));
		
		return Boolean.TRUE;
	}

	@Transactional
	public Collection createCollection(CollectionEditDTO collectionEditDTO) {
		log.info("collectionEditDTO : {} " , JSONUtils.toJsonString(collectionEditDTO));
		
		Collection collection = null ; 
		if(collectionEditDTO.getCollectionId() != null) {
			collection = collectionRepository.findCollection(collectionEditDTO.getCollectionId());
		}
		if(collection == null) collection = new Collection();
		collection.setBanners(collectionEditDTO.getBanners());
		collection.setComments(collectionEditDTO.getComments());
		collection.setName(collectionEditDTO.getName());
		collection.setPresentId(collectionEditDTO.getPresentId());
		collectionRepository.save(collection);
		
		collectionProductRepository.deleteByCollectionId(collection.getId());
		
		List<ProductDTO> productDTOs = collectionEditDTO.getProductDTOs();
		
		if(productDTOs != null && !productDTOs.isEmpty()) {
			
			Set<Long> productIds = new LinkedHashSet<>();
			for (ProductDTO productDTO : productDTOs) {
				productIds.add(productDTO.getId());
			}
			
			ArrayList<Long> lists = CollectionUtil.newArrayList(productIds);
			
			List<CollectionProduct> collectionProducts = new ArrayList<>();
			
			for(int i = 0 ; i < lists.size() ; i++) {
				collectionProducts.add(new CollectionProduct(collection.getId(), lists.get(i), i));
			}
			collectionProductRepository.saveAll(collectionProducts);
		}
		return collection;
	}
	
	@Transactional
	public Collection copyCollection(CollectionRequest collectionRequest) {

		Collection collection = collectionRepository.findCollection(collectionRequest.getCollectionId());
		Preconditions.checkArgument(collection != null, "模块不存在...");
		
		Collection newCollection = new Collection();
		BeanUtils.copyProperties(collection, newCollection, "id" , "yn" , "createdAt" , "updatedAt");
		newCollection.setName(collectionRequest.getName());
		newCollection.setComments("从["+collection.getName()+"]复制创建");
		collectionRepository.save(newCollection);
		
		List<CollectionProduct> newCollectionProducts = new ArrayList<>();
		List<CollectionProduct> collectionProducts = collectionProductRepository.findCollectionProduct(collectionRequest.getCollectionId());
		for (CollectionProduct collectionProduct : collectionProducts) {
			CollectionProduct product = new CollectionProduct();
			BeanUtils.copyProperties(collectionProduct, product, "id" , "collectionId");
			product.setCollectionId(newCollection.getId());
			newCollectionProducts.add(product);
		}
		collectionProductRepository.saveAll(newCollectionProducts);
		return newCollection;
	} 
	
	@Transactional
	public Collection commentCollection(CollectionRequest collectionRequest) {

		Collection collection = collectionRepository.findCollection(collectionRequest.getCollectionId());
		Preconditions.checkArgument(collection != null, "模块不存在...");
		
		collection.setComments(collectionRequest.getComments());
		return collectionRepository.save(collection);
	}
	
	@Transactional
	public Collection coverImgCollection(CollectionEditDTO collectionRequest) {

		Collection collection = collectionRepository.findCollection(collectionRequest.getCollectionId());
		Preconditions.checkArgument(collection != null, "模块不存在...");
		
		collection.setCoverImg(collectionRequest.getCoverImg().trim());
		return collectionRepository.save(collection);
	}
	
	@Transactional
	public void coverImgCollections(CollectionCoverDTO collectionCoverDTO) {

		for (Long collectionId : collectionCoverDTO.getCollectionIds()) {
			Collection collection = collectionRepository.findCollection(collectionId);
			Preconditions.checkArgument(collection != null, "模块不存在...");
			
			collection.setCoverImg(collectionCoverDTO.getCoverImg().trim());
			collectionRepository.save(collection);
		}
	}
	
}
